package com.jrx.anytxn.investor.service.impl;

import com.jrx.anytxn.common.function.UncheckedFunction;
import com.jrx.anytxn.common.uitl.CollectorsUtils;
import com.jrx.anytxn.investor.constant.TransBizConstant;
import com.jrx.anytxn.investor.entity.*;
import com.jrx.anytxn.investor.mapper.base.TlPaymentInvestorLogMapper;
import com.jrx.anytxn.investor.mapper.ext.ExtAmLoanMainInvestorInfoMapper;
import com.jrx.anytxn.investor.mapper.ext.ExtTlMistakeInvestorLogMapper;
import com.jrx.anytxn.investor.mapper.ext.ExtTlPaymentAllocationInvestorLogMapper;
import com.jrx.anytxn.investor.mapper.ext.ExtTlPaymentInvestorMappingMapper;
import com.jrx.anytxn.investor.service.IInvestorDealPaymentService;
import com.jrx.anytxn.investor.service.IInvestorMistakeService;
import com.jrx.anytxn.investor.service.IInvestorPaymentService;
import com.jrx.anytxn.number.service.ISegmentService;
import com.jrx.anytxn.param.entity.PrOrganizationTable;
import com.jrx.anytxn.param.service.system.IOrganizationTableService;
import com.jrx.anytxn.redisson.service.RedissonLockService;
import com.jrx.anytxn.redisson.util.LockType;
import com.jrx.anytxn.transaction.entity.TlPaymentAllocationLog;
import org.apache.commons.collections.CollectionUtils;
import org.redisson.api.RLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @program: anytxn-cf-transaction
 * @description:
 * @author: xiaoyu.jing
 * @date: 2020-05-27 19:11
 **/
@Service
public class InvestorPaymentServiceImpl implements IInvestorPaymentService {

    private static final Logger logger = LoggerFactory.getLogger(InvestorPaymentServiceImpl.class);

    @Resource
    private ExtTlMistakeInvestorLogMapper extTlMistakeInvestorLogMapper;
    @Autowired
    private IInvestorMistakeService mistakeService;
    @Autowired
    private IOrganizationTableService organizationTableService;
    @Autowired
    private IInvestorDealPaymentService dealPaymentService;
    @Resource
    private ExtAmLoanMainInvestorInfoMapper extAmLoanMainInvestorInfoMapper;
    @Autowired
    private ISegmentService segmentService;
    @Resource
    private ExtTlPaymentInvestorMappingMapper extTlPaymentInvestorMappingMapper;
    @Autowired
    private RedissonLockService redissonLockService;
    @Resource
    private ExtTlPaymentAllocationInvestorLogMapper extTlPaymentAllocationInvestorLogMapper;

    @Override
    public void paymentAllocation(TlPaymentInvestorLog paymentLog) throws Exception {

        String lockKey = String.format(TransBizConstant.INVESTOR_REDIS_LOCK, paymentLog.getTenantId(),
                paymentLog.getCustomerId(), paymentLog.getLoanId());
        RLock lock = redissonLockService.getRLock(lockKey, LockType.REENTRANT_LOCK);
        try {
            boolean lockFlag = lock.tryLock(TransBizConstant.PAYMENT_REDIS_LOCK_WAITE_TIME,
                    TransBizConstant.PAYMENT_REDIS_LOCK_LESS_TIME, TimeUnit.SECONDS);

            //判断是否存在差错
            List<TlMistakeInvestorLog> mistakeLogList = extTlMistakeInvestorLogMapper.selectMistake( paymentLog.getCustomerId(),
                    paymentLog.getTenantId(), TransBizConstant.MIS_STATUS_0);

            if (CollectionUtils.isNotEmpty(mistakeLogList)) {
                for(TlMistakeInvestorLog mistakeLog : mistakeLogList ) {
                    if (!paymentLog.getSeqNo().equals(mistakeLog.getOrgiSeqNo())) {
                        throw new Exception("原订单已有差错");
                    }
                }
                return;
            }

            if (!lockFlag) {
                throw new Exception("锁竞争失败差错");
            }

            //获取所有资金方贷款订单信息
            List<AmLoanMainInvestorInfo> loanMainList = extAmLoanMainInvestorInfoMapper.findInvestorLoan(paymentLog.getLoanId(), paymentLog.getCustomerId(), paymentLog.getTenantId());

            List<TlPaymentInvestorMapping> mappingList = extTlPaymentInvestorMappingMapper.selectBySeqNo(paymentLog.getSeqNo(),paymentLog.getCustomerId(), paymentLog.getTenantId());
            UncheckedFunction<AmLoanMainInvestorInfo, TlPaymentInvestorMapping> createMapping = loanMain -> {
                TlPaymentInvestorMapping mapping = new TlPaymentInvestorMapping();
                BeanUtils.copyProperties(paymentLog, mapping);
                mapping.setId(segmentService.getId(TransBizConstant.TL_PAYMENT_INVESTOR_MAPPING));
                mapping.setInvestorId(loanMain.getInvestorId());
                mapping.setInvestorLoanId(loanMain.getInvestorLoanId());
                mapping.setCreateTime(null);
                return mapping;
            };

            if(CollectionUtils.isEmpty(mappingList)) {
                mappingList = loanMainList.stream().map(CollectorsUtils.tranToUncheck(createMapping)).collect(Collectors.toList());
                extTlPaymentInvestorMappingMapper.batchInsert(mappingList);
            }
            Date bussinessDate = null;
            try {
                PrOrganizationTable organization =
                        organizationTableService.findByOrId(paymentLog.getOrganizationId(), paymentLog.getTenantId());
                bussinessDate = organization.getNextProcessingDate();
                this.dealAllocation(paymentLog, loanMainList, bussinessDate);
            } catch (Exception e) {
                //还款出现异常保存差错，后续进行差错处理
                logger.error("还款分配发生异常", e);
                TlMistakeInvestorLog mistakeLog = mistakeService.buildMistakeLog(paymentLog, bussinessDate);
                extTlMistakeInvestorLogMapper.insertSelective(mistakeLog);
                return;
            }
        }  finally {
            lock.unlock();
        }

        logger.info("还款分配结束");
    }

    @Override
    public void dealAllocation(TlPaymentInvestorLog paymentLog, List<AmLoanMainInvestorInfo> loanMainList, Date bussinessDate) throws Exception {
        logger.info("开始还款分配");
        List<TlPaymentAllocationInvestorLog> tlPaymentAllocationLogList = extTlPaymentAllocationInvestorLogMapper.findAllocationLogs(paymentLog.getSeqNo(), paymentLog.getCustomerId(),paymentLog.getTenantId());
        if(CollectionUtils.isNotEmpty(tlPaymentAllocationLogList)){
            return;
        }

        String paymentType = paymentLog.getPaymentType();
        if (TransBizConstant.REPAYMENT_TYPE_PREPAY.equals(paymentType)) {
            //提前还款
            dealPaymentService.dealPrePay(paymentLog, loanMainList, bussinessDate);
        } else if (TransBizConstant.REPAYMENT_TYPE_PRETERMINTION.equals(paymentType)) {
            //提前结清
            dealPaymentService.dealPayOff(paymentLog, loanMainList, bussinessDate);
        } else if (TransBizConstant.REPAYMENT_TYPE_OVERDUE.equals(paymentType)) {
            //逾期还款
            dealPaymentService.dealOverPay(paymentLog, loanMainList, bussinessDate);
        } else if (TransBizConstant.REPAYMENT_TYPE_AUTO.equals(paymentType)) {
            //批扣
            dealPaymentService.dealPay(paymentLog, loanMainList, bussinessDate);
        } else if (TransBizConstant.REPAYMENT_TYPE_PAY.equals(paymentType)) {
            //正常还款
            dealPaymentService.dealPay(paymentLog, loanMainList, bussinessDate);
        } else if (TransBizConstant.REPAYMENT_TYPE_CMPS.equals(paymentType)) {
            //代偿
            dealPaymentService.dealCmpsPay(paymentLog, loanMainList, bussinessDate);
        } else if (TransBizConstant.REPAYMENT_TYPE_CRT.equals(paymentType)) {
            //回购
            dealPaymentService.dealCrtPay(paymentLog, loanMainList, bussinessDate);
        } else if(TransBizConstant.REPAYMENT_TYPE_WAIVEAUTO.equals(paymentType)){
            //贴息分配
            dealPaymentService.dealPay(paymentLog, loanMainList, bussinessDate);
        }
    }
}
